﻿using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Media;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;

namespace Peter.Logic.AvalonEdit
{
   /// <summary>
   /// A background renderer for colors.
   /// </summary>
   public class ColorBackgroundRenderer : IBackgroundRenderer
   {
      private MatchCollection m_Matches;
      private readonly TextEditor m_Editor;

      /// <summary>
      /// Initializes a new Highlight Current Line Background Renderer
      /// </summary>
      /// <param name="editor">The editor to attach to.</param>
      public ColorBackgroundRenderer (TextEditor editor)
      {
         this.m_Editor = editor;
         this.m_Editor.TextChanged += this.OnTextChanged;
         this.m_Editor.DocumentChanged += this.OnTextChanged;
         this.Add ();
      }

      /// <summary>
      /// Gets the layer to draw this on.
      /// </summary>
      public KnownLayer Layer
      {
         get { return KnownLayer.Background; }
      }

      /// <summary>
      /// Adds this background renderer to the stack.
      /// </summary>
      public void Add ()
      {
         if (!this.m_Editor.TextArea.TextView.BackgroundRenderers.Contains (this))
            this.m_Editor.TextArea.TextView.BackgroundRenderers.Add (this);
      }

      /// <summary>
      /// Removes this background renderer from the stack.
      /// </summary>
      public void Remove ()
      {
         if (this.m_Editor.TextArea.TextView.BackgroundRenderers.Contains (this))
            this.m_Editor.TextArea.TextView.BackgroundRenderers.Remove (this);
      }

      /// <summary>
      /// Draws the line highlight
      /// </summary>
      /// <param name="textView">The text view with the line highlighted.</param>
      /// <param name="drawingContext"></param>
      public void Draw (TextView textView, DrawingContext drawingContext)
      {
         if (this.m_Matches != null && this.m_Matches.Count > 0) {
            textView.EnsureVisualLines ();
            foreach (Match match in this.m_Matches) {
               var colorFromValue = ColorConverter.ConvertFromString (match.Value);
               if (colorFromValue != null) {
                  var color = (Color)colorFromValue;
                  var brush = new SolidColorBrush (color);
                  UnderlineColor (textView, drawingContext, match.Index, match.Length, new Pen (brush, 2));
               }
            }
         }
      }

      /// <summary>
      /// Occurs when the text in the document changes.
      /// </summary>
      /// <param name="sender">The editor.</param>
      /// <param name="e">Event Arguments.</param>
      private async void OnTextChanged (object sender, EventArgs e)
      {
         var text = this.m_Editor.Text;
         this.m_Matches = await Task.Run(() => Regex.Matches (text, "#([a-f0-9]{8}|[a-f0-9]{6}|[a-f0-9]{3})", RegexOptions.IgnoreCase));
      }

      /// <summary>
      /// Highlights the character at the given offset.
      /// </summary>
      /// <param name="textView">Text view to highlight character at.</param>
      /// <param name="drawingContext">Drawing context used to highlight.</param>
      /// <param name="offset">Offset at which to highlight.</param>
      /// <param name="length">The length to highlight.</param>
      /// <param name="pen">The pen to use for underlining.</param>
      private static void UnderlineColor (TextView textView, DrawingContext drawingContext, int offset, int length, Pen pen)
      {
         var segment = new TextSegment { StartOffset = offset, EndOffset = offset + length };
         foreach (var r in BackgroundGeometryBuilder.GetRectsForSegment (textView, segment))
            drawingContext.DrawLine(pen, r.BottomLeft, r.BottomRight);//.DrawRectangle (brush, null, new Rect (r.BottomLeft, r.Size));
      }
   }
}
